package com.sam.designpatterns

import java.util.*


abstract class ArithmeticExpression {
    /**
     * 抽象的解析方法
     * 具体的解析逻辑同具体的子类实现
     * @return 解析得到具体的值
     */
    abstract fun interpret(): Int
}

// 数字解释器，仅仅是为了解释数字
class NumberExpression(val value: Int) : ArithmeticExpression() {
    override fun interpret(): Int {
        return value
    }
}

// 运算符号抽象解释器
abstract class OperatorExpression(
        // 存储运算符两边的数字
        val exp1: ArithmeticExpression,
        val exp2: ArithmeticExpression
) : ArithmeticExpression()

// 加法运算解释器
class AdditionExpression(exp1: ArithmeticExpression, exp2: ArithmeticExpression)
    : OperatorExpression(exp1, exp2) {
    override fun interpret(): Int {
        return exp1.interpret() + exp2.interpret()
    }
}

// 减法运算解释器
class SubtractionExpression(exp1: ArithmeticExpression, exp2: ArithmeticExpression)
    : OperatorExpression(exp1, exp2) {
    override fun interpret(): Int {
        return exp1.interpret() - exp2.interpret()
    }
}

class Calculator {

    // 计算表达式如 calc("1 + 1")
    fun calc(expression: String) :Int{
        // 存储并操作所有相关的解释器
        val stack = Stack<ArithmeticExpression>()
        val elements = expression.split(" ")
        var i = 0
        while (i <= elements.lastIndex) {
            val element = elements[i]
            when (element) {
                "+", "-" -> { // 是符号
                    // 栈顶的解释器作为计算式左边的一个数字解释器
                    val exp1 = stack.pop()
                    // 数组下一个元素为计算式右边的数字解释器
                    val exp2 = NumberExpression(elements[++i].toInt())
                    val operatorExpression = if (element == "+") {
                        AdditionExpression(exp1, exp2)
                    } else {
                        SubtractionExpression(exp1, exp2)
                    }
                    stack.push(operatorExpression)
                }
                else -> { // 是数字
                    stack.push(NumberExpression(element.toInt()))
                }
            }
            i++
        }

        return stack.pop().interpret()
    }

}

fun main() {
    val calculator = Calculator()
    val express = "2021 + 3 + 1 - 1359"
    print("$express = ${calculator.calc(express)}")
}